/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package idp.communication;

import idp.dashboard.MainFrame;
import idp.dashboard.MainPanel;
import idp.exceptions.BluetoothConnectionException;
import idp.exceptions.InstanceAlreadyExsistsException;
import idp.exceptions.UserCanceledActionException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.StreamConnection;

import com.intel.bluetooth.BlueCoveImpl;

/**
 * Handles all aspects of the bluetooth connection. Will call
 * {@link BluetoothConnection} and start the {@link MessageController}. This
 * class is a singleton.
 * 
 * @see BluetoothConnection
 * @see MessageController
 * 
 * @author R. Schaafmsa
 */
public class CommunicationController extends Thread {

	// reference to the current instance of CommunicationController.
	private static CommunicationController _instance;

	private StreamConnection _conn;

	private OutputStream _output;

	private InputStream _input;

	private BluetoothConnection _bluetoothConnection;

	private MessageController _msgController;

	private boolean _quit = false, _connected = false,
			_connectionError = false;

	/**
	 * Constructor for the communication. Will setup the bluetooth connection.
	 * Does not actually connect to the other device. Please call connect() to
	 * do that.
	 * 
	 * @throws UserCanceledActionException
	 * @see {@link #connect()}
	 */
	public CommunicationController() throws UserCanceledActionException {
		super("CommunicationController");
		// get the BluetoothConnection instance and find the bleutooth device
		_bluetoothConnection = BluetoothConnection.getInstance();	
		_instance = this;
	}

	/**
	 * Connect to the Remote bluetooth device. If it fails it will ask is the
	 * user wants to try again. Throws an UserCanceledActionException if the
	 * user doesn't want to continue after a failure.
	 * 
	 * 
	 * @throws UserCanceledActionException
	 */
	public void connect() {
		// boolean connected = false;
		try {
			_bluetoothConnection.choseDevice();
		} catch (UserCanceledActionException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		while (!_quit) {
			try {
				if (!_connected) {
					_conn = _bluetoothConnection.connect(); // throws exception
															// if
					_connected = true; // connection failed
					System.out.println("BT connected");
					MainFrame.getInstance().dashboard.setConnection(_connected);

					// create and start (if needed) the MessageController.
					try {
						_msgController = new MessageController(_conn);
					} catch (InstanceAlreadyExsistsException e) {
						System.out.println("instance already exists");
						_msgController = MessageController.getInstance();
					}
					if (!_msgController.isAlive()) {
						_msgController.start();
					}
				} else {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
					}
				}
				 if(_connectionError){
				 throw new BluetoothConnectionException("connection error");
				 }
			} catch (BluetoothConnectionException bce) {
				_connected = false;
				_connectionError = false;
				MainFrame.getInstance().dashboard.setConnection(_connected);
				if(_msgController != null){
					_msgController.Quit();
					_msgController.stop();
				}
				if (!idp.utils.UserInput.getUserYesNO(bce.getMessage()
						+ ", Wilt u het opnieuw proberen?")) {
					Quit();
					// throw new UserCanceledActionException(
					// "Connection failed. User canceled reconnect attemtps");
				}
			}
		}
		_connected = false;
		_bluetoothConnection = null;
		if(_msgController != null){
			_msgController.Quit();
			try {
				sleep(1000);
			} catch (InterruptedException e) {}
			if(_msgController.isAlive()){
				_msgController.stop();
			}
		}
		BlueCoveImpl.shutdown();
		MainFrame.getInstance().dashboard.setConnection(_connected);
	}

	public boolean isConnected() {
		return _connected;
	}

	public void run() {
		connect();
	}

	public void Quit() {
		_instance = null;
		_quit = true;				
	}

	/**
	 * Return the inputStream.
	 * 
	 * @return the input stream
	 */
	public InputStream getInput() {
		return this._input;
	}

	/**
	 * Returns the current instance of CommunicationController. Creates a new
	 * instance if none exists.
	 * 
	 * @return the current CommunicationController instance
	 * @throws UserCanceledActionException
	 */
	public static CommunicationController getInstance()			{
		if (_instance == null) {
			try {
				new CommunicationController();
			} catch (UserCanceledActionException e) {
				// TODO Auto-generated catch block				
			}
		}
		return _instance;
	}

	public void connectionError() {
		_connectionError = true;		
	}

}
